//
// Copyright (C) 2022-2023 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0

package spinning

import (
	"fmt"
	"net/http"
	"net/url"

	mqtt "github.com/eclipse/paho.mqtt.golang"
	_ "github.com/mattn/go-sqlite3"

	"github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/interfaces"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger"
	"github.com/pkg/errors"
)

type SpinningApp struct {
	service    interfaces.ApplicationService
	lc         logger.LoggingClient
	config     *ServiceConfig
	mqttClient mqtt.Client
	fileServer http.Handler

	mcuSettings McuSettings // 全局存放 机台配置参数
	mcuRealtime McuRealtime // 全局存放 机台实时状态
	mcuSpindles []Spindle   // 全局存放 异常锭子实时状态

	doffing       Doffing // 当前 纺纱周期
	stop          Stop    // 当前 停车记录
	topicSettings string
	topicRealtime string
	topicSpindles string
	topicVoltages string
	topicCommand  string

	currentVoltagesCmd EdgexCmd             // 一次只允许一个事务执行
	currentVoltagesRes McuVoltages_Response // 当前事务 锭子电压波形数据
}

const (
	//brokerUrl  = "192.168.0.248"
	brokerUrl  = "127.0.0.1"
	brokerPort = 1883
	username   = "admin"
	password   = "public"
)

var mqttClientId = "Spinning-Client"
var topicSettings string = "edgex/event/mcu/settings"
var topicRealtime string = "edgex/event/mcu/realtime"
var topicSpindles string = "edgex/event/mcu/spindles"
var topicVoltages string = "edgex/event/mcu/voltages"
var topicCommand string = "edgex/event/to_mcu/command"

func NewSpinningApp(service interfaces.ApplicationService) *SpinningApp {
	return &SpinningApp{
		service:       service,
		lc:            service.LoggingClient(),
		config:        &ServiceConfig{},
		topicSettings: "edgex/event/mcu/settings",
		topicRealtime: "edgex/event/mcu/realtime",
		topicSpindles: "edgex/event/mcu/spindles",
		topicVoltages: "edgex/event/mcu/voltages",
		topicCommand:  "edgex/event/mcu/command",
	}
}

func (app *SpinningApp) Run() error {

	if err := app.service.LoadCustomConfig(app.config, "AppCustom"); err != nil {
		return errors.Wrap(err, "failed to load custom configuration")
	}

	/*
		err1 := app.service.AddFunctionsPipelineForTopics(topicSettings, []string{topicSettings}, app.handleMcuSettingsMsg)
		if err1 != nil {
			app.service.LoggingClient().Errorf("AddFunctionsPipelineForTopic: %s, Error: %s", topicSettings, err1.Error())
			os.Exit(-1)
		}

		err2 := app.service.AddFunctionsPipelineForTopics(topicRealtime, []string{topicRealtime}, app.handleMcuRealtimeMsg)
		if err2 != nil {
			app.service.LoggingClient().Errorf("AddFunctionsPipelineForTopic: %s,  Error: %s", topicRealtime, err2.Error())
			os.Exit(-1)
		}

		err3 := app.service.AddFunctionsPipelineForTopics(topicSpindles, []string{topicSpindles}, app.handleMcuSpindlesMsg)
		if err3 != nil {
			app.service.LoggingClient().Errorf("AddFunctionsPipelineForTopic: %s, Error: %s", topicSpindles, err3.Error())
			os.Exit(-1)
		}

		err4 := app.service.AddFunctionsPipelineForTopics(topicVoltages, []string{topicVoltages}, app.handleMcuSpindleVoltageMsg)
		if err4 != nil {
			app.service.LoggingClient().Errorf("AddFunctionsPipelineForTopic: %s, Error: %s", topicVoltages, err4.Error())
			os.Exit(-1)
		}
	*/

	uri := &url.URL{
		Scheme: "tcp",
		Host:   fmt.Sprintf("%s:%d", brokerUrl, brokerPort),
		User:   url.UserPassword(username, password),
	}

	var err5 error = nil
	err5 = app.initialMqttClient(mqttClientId, uri)
	if err5 != nil {
		fmt.Println(err5)
	}

	if err := app.addRoutes(); err != nil {
		return err
	}

	if err := app.service.MakeItRun(); err != nil {
		return errors.Wrap(err, "failed to run pipeline")
	}

	return nil
}

func (app *SpinningApp) initialMqttClient(clientID string, uri *url.URL) error {
	fmt.Printf("### Create MQTT client and connection: uri=%v clientID=%v ###\n", uri.String(), clientID)
	opts := mqtt.NewClientOptions()
	opts.AddBroker(fmt.Sprintf("%s://%s", uri.Scheme, uri.Host))
	opts.SetClientID(clientID)
	opts.SetUsername(uri.User.Username())
	password, _ := uri.User.Password()
	opts.SetPassword(password)
	opts.SetConnectionLostHandler(func(client mqtt.Client, e error) {
		fmt.Printf("Connection lost : %v", e)
		token := client.Connect()
		if token.Wait() && token.Error() != nil {
			fmt.Printf("Reconnection failed : %v", e)
		} else {
			fmt.Printf("Reconnection sucessful : %v", e)
		}
	})

	app.mqttClient = mqtt.NewClient(opts)
	fmt.Println("### createMqttClient ###")
	token := app.mqttClient.Connect()
	if token.Wait() && token.Error() != nil {
		fmt.Printf("### mqttClient.Connect failed: %s ###", token.Error())
		return token.Error()
	}

	// t1 := app.mqttClient.Subscribe(topicRealtime, byte(0), app.handleMqttRealtimeMsg)
	// if t1.Wait() && t1.Error() != nil {
	// 	fmt.Println(token.Error())
	// }

	// t2 := app.mqttClient.Subscribe(topicSettings, byte(0), app.handleMqttSettingsMsg)
	// if t2.Wait() && t2.Error() != nil {
	// 	fmt.Println(t2.Error())
	// }

	// t3 := app.mqttClient.Subscribe(topicSpindles, byte(0), app.handleMqttSpindlesMsg)
	// if t3.Wait() && t3.Error() != nil {
	// 	fmt.Println(t3.Error())
	// }

	t4 := app.mqttClient.Subscribe(topicVoltages, byte(0), app.handleMqttSpindleVoltageMsg)
	if t4.Wait() && t4.Error() != nil {
		fmt.Println(t4.Error())
	}
	fmt.Printf("### mqttClient.Subscribe: %s ###\n", topicVoltages)
	return nil
}
